package com.ruoyi.business.service.impl;

import com.ruoyi.business.domain.DefinitionDetail;
import com.ruoyi.business.service.IProcessService;
import com.ruoyi.common.utils.StringUtils;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.zip.ZipInputStream;

/**
 * Created by wolfcode-lanxw
 */
@Service
public class ProcessServiceImpl implements IProcessService {
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService historyService;

    /**
     * 通过获取到的filePath来进行流程定义的部署
     * @param filePath
     * @return
     * @throws FileNotFoundException
     */
    @Override
    public Deployment deploy(String filePath) throws FileNotFoundException {
        Deployment deployment = null;
        if(filePath.endsWith("zip")){
            ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(filePath));
            deployment = repositoryService.createDeployment()
                    .addZipInputStream(zipInputStream)
                    .deploy();
        }else {
            deployment = repositoryService.createDeployment()
                    .addInputStream(filePath, new FileInputStream(filePath))
                    .deploy();
        }
        return deployment;
    }


    /**
     * 通过部署id查询流程定义
     * @param deploymentId
     * @return
     */
    @Override
    public ProcessDefinition selectProcessDefinitionByDeploymentId(String deploymentId) {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploymentId)
                .singleResult();
        return processDefinition;
    }

    /**
     * 通过部署id获取bpmn输入流
     * @param deploymentId
     * @return
     */
    @Override
    public InputStream getBpmnInputStream(String deploymentId) {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
        return repositoryService.getResourceAsStream(deploymentId,processDefinition.getResourceName());
    }

    /**
     * 通过部署id获取png输入流
     * @param deploymentId
     * @return
     */
    @Override
    public InputStream getPngInputStream(String deploymentId) {
        //通过部署id获取流程定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
        //通过流程定义id获取bpmnModal
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        DefaultProcessDiagramGenerator defaultProcessDiagramGenerator = new DefaultProcessDiagramGenerator();
        InputStream inputStream = defaultProcessDiagramGenerator.generateDiagram(bpmnModel, Collections.EMPTY_LIST, Collections.EMPTY_LIST, "宋体", "宋体", "宋体");
        //将bpmn转换为png
        return inputStream;
    }

    /**
     * 传入对应的参数发起流程实例
     * @param definitionKey
     * @param businessKey
     * @param variables
     * @return
     */
    @Override
    public ProcessInstance startProcessInstance(String definitionKey, String businessKey, HashMap<String, Object> variables) {
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(definitionKey, businessKey, variables);
        return processInstance;
    }

    /**
     * 通过实例id查询任务节点
     * @param processInstanceId
     * @return
     */
    @Override
    public Task selectTaskByProcessInstanceId(String processInstanceId) {
        return taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
    }

    /**
     * 往节点中设置候选人
     * @param currentTask
     * @param userId
     */
    @Override
    public void addCandidateUser(Task currentTask, Long userId) {
        taskService.addCandidateUser(currentTask.getId(),userId.toString());
    }

    /**
     * 根据实例id获取流程图png,并高亮节点
     * @param instanceId
     * @return
     */
    @Override
    public InputStream getProcessImgInputByInstanceId(String instanceId) {
        //通过实例id获取历史流程实例
        HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(instanceId).singleResult();
        //通过流程定义id获取bpmn
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
        //查询流程实例
        ProcessInstance instance = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).singleResult();
        //获取正在活动的节点
        List<String> activeActivityIds = null;
        if(instance != null){ //判断流程实例是否存在,如果存在,表示有活动的节点
            activeActivityIds = runtimeService.getActiveActivityIds(processInstance.getId());
        }else {
            activeActivityIds = Collections.EMPTY_LIST;
        }
        DefaultProcessDiagramGenerator defaultProcessDiagramGenerator = new DefaultProcessDiagramGenerator();
        InputStream inputStream = defaultProcessDiagramGenerator.generateDiagram(bpmnModel, activeActivityIds, Collections.EMPTY_LIST, "宋体", "宋体", "宋体");
        return inputStream;
    }

    /**
     * 根据实例ID获取流程实例
     * @param instanceId
     * @return
     */
    @Override
    public ProcessInstance getProcessInstanceByInstanceId(String instanceId) {
        return runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).singleResult();
    }

    /**
     * 删除流程实例
     * @param processInstanceId
     */
    @Override
    public void deleteProcessInstanceByInstanceId(String processInstanceId) {
        runtimeService.deleteProcessInstance(processInstanceId,"审核撤销");
    }

    /**
     * 查询当前用户的待办任务总数
     * @param definitionKey
     * @param userId
     * @return
     */
    @Override
    public long selectTodoTaskCount(String definitionKey, String userId) {
        long count = taskService.createTaskQuery()
                .processDefinitionKey(definitionKey)
                .taskCandidateUser(userId)
                .count();
        return count;
    }

    /**
     * 根据流程定义id查询当前用户的待办任务集合
     * @param definitionKey
     * @param userId
     * @return
     */
    @Override
    public List<Task> selectTodoTaskList(String definitionKey, String userId,Integer pageNum,Integer pageSize) {
        List<Task> list = taskService.createTaskQuery()
                .processDefinitionKey(definitionKey)
                .taskCandidateUser(userId)
                .orderByTaskCreateTime()
                .desc()
                .listPage(pageNum,pageSize);
        return list;
    }

    /**
     * 通过流程实例id获取流程实例
     * @param processInstanceId
     * @return
     */
    @Override
    public ProcessInstance selectProcessInstanceByProcessInstanceId(String processInstanceId) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
        return processInstance;
    }

    /**
     * 根据任务节点id获取任务节点
     * @param taskId
     * @return
     */
    @Override
    public Task selectTaskByTaskId(String taskId) {
        return taskService.createTaskQuery().taskId(taskId).singleResult();
    }

    /**
     * 任务的认领和处理
     * @param task
     * @param userId
     * @param auditStatus
     * @param comment
     */
    @Override
    public void claimAndComplete(Task task, Long userId, Boolean auditStatus, String comment) {
        String commentStr = auditStatus ? "[同意]" : "[拒绝]";
        commentStr += comment;  //审核意见

        //领取任务
        taskService.claim(task.getId(),userId.toString());
        //添加批注
        taskService.addComment(task.getId(),task.getProcessInstanceId(),commentStr);
        //添加流程变量
//        HashMap<String, Object> variables = new HashMap<>();
//        variables.put(task.getTaskDefinitionKey(),auditStatus);
        taskService.setVariable(task.getId(),task.getTaskDefinitionKey(),auditStatus);
        //处理任务
        taskService.complete(task.getId());
    }

    @Override
    public void claimAndComplete(Task task, Long userId, String comment) {

        //领取任务
        taskService.claim(task.getId(),userId.toString());
        //添加批注
        taskService.addComment(task.getId(),task.getProcessInstanceId(),comment);
        //处理任务
        taskService.complete(task.getId());
    }

    /**
     * 设置流程变量
     * @param taskId
     * @param key
     * @param value
     */
    @Override
    public void setVariable(String taskId,String key, long value) {
        taskService.setVariable(taskId,key,value);
    }

    /**
     * 查询已办任务总数
     * @param definitionKey
     * @param userId
     * @return
     */
    @Override
    public long selectDoneTaskCount(String definitionKey, String userId) {
        long count = historyService.createHistoricTaskInstanceQuery()
                .processDefinitionKey(definitionKey)
                .taskAssignee(userId)
                .finished()  //已办任务 == 流程结束
                .count();
        return count;
    }

    /**
     * 查询已办任务集合
     * @param definitionKey
     * @param userId
     * @param startNum
     * @param pageSize
     * @return
     */
    @Override
    public List<HistoricTaskInstance> selectDoneTaskList(String definitionKey, String userId, Integer startNum, Integer pageSize) {
        List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery()
                .processDefinitionKey(definitionKey)
                .taskAssignee(userId)
                .finished()
                .orderByHistoricTaskInstanceEndTime()
                .desc()
                .listPage(startNum, pageSize);
        return historicTaskInstances;
    }

    /**
     * 根据流程实例id获取历史流程实例
     * @param processInstanceId
     * @return
     */
    @Override
    public HistoricProcessInstance selectHistoryProcessInstanceById(String processInstanceId) {
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(processInstanceId)
                .singleResult();
        return historicProcessInstance;
    }

    /**
     * 根据实例id查询历史活动节点
     * @param instanceId
     * @return
     */
    @Override
    public List<HistoricActivityInstance> selectHistoricActivityInstanceByInstanceId(String instanceId) {
        List<HistoricActivityInstance> userTask = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(instanceId)
                .activityType("userTask")
                .finished()
                .orderByHistoricActivityInstanceStartTime()
                .desc()
                .list();
        return userTask;
    }

    /**
     * 根据任务id查询批注
     * @param taskId
     * @return
     */
    @Override
    public String selectCommentByTaskId(String taskId) {
        List<Comment> taskComments = taskService.getTaskComments(taskId);
        if(StringUtils.isNotEmpty(taskComments)){
            return taskComments.get(0).getFullMessage();
        }else {
            return "";
        }
    }

}
